﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;
using System.IO;
using System.Xml;

namespace WindowsFormsApplication1.FindFriends
{
    public class FindFriendsRequest
    {
        public ServerSocketData _requesterServer;
        public int friendsOfCharacterId = -1;
        public List<int> friendIdsToFind = new List<int>();

        private List<FindFriendsResult> results = new List<FindFriendsResult>();
        
        //We will only wait 3 seconds, and then assume any world servers that havent responded are down or having issues.
        private Timer timerRequestTimeout = new Timer(1000 * 3);

        public FindFriendsRequest(ServerSocketData requestingServer)
        {
            _requesterServer = requestingServer;
            timerRequestTimeout.AutoReset = false;
            timerRequestTimeout.Elapsed += new ElapsedEventHandler(timerRequestTimeout_Elapsed);
            timerRequestTimeout.Start();
        }

        private void timerRequestTimeout_Elapsed(object sender, ElapsedEventArgs e)
        {
            Managers.findFriendsManager.completeRequest(this);
        }

        public void sendRequests()
        {
            List<ServerSocketData> servers = Managers.socketConnectionsManager.GetServerSocketsCpy();
            servers.Remove(_requesterServer);

            if (servers.Count == 0)
            {
                //Complete this request because there are no servers to query
                Managers.findFriendsManager.completeRequest(this);
                return;
            }

            //Build a list of results we expect to recieve
            foreach (ServerSocketData server in servers)
            {
                FindFriendsResult result = new FindFriendsResult(server);
                results.Add(result);
            }

            StringWriter stringWriter = new StringWriter();
            XmlTextWriter xmldoc = new XmlTextWriter(stringWriter);
            xmldoc.WriteStartElement("findfriendsPS");
            xmldoc.WriteAttributeString("friendsofId", friendsOfCharacterId.ToString());

            foreach (int characterId in friendIdsToFind)
            {
                xmldoc.WriteStartElement("friend");
                xmldoc.WriteAttributeString("id", characterId.ToString());
                xmldoc.WriteEndElement();
            }

            xmldoc.WriteEndElement();
            xmldoc.Flush();
            xmldoc.Close();
            stringWriter.Flush();
            string xmlMessage = stringWriter.ToString();

            //Send request out to all servers
            foreach (ServerSocketData ssd in servers)
            {
                //If send to this server failed, remove its expected result
                if (SocketConnectionsManager.sendToServer(ssd, xmlMessage) == false)
                {
                    lock (results)
                    {
                        foreach (FindFriendsResult result in results)
                        {
                            if (result.server == ssd)
                            {
                                results.Remove(result);
                                break;
                            }
                        }
                        //If the send took a while to fail, we may have already gotten all responses, so we need to check
                        bool allComplete = true;
                        foreach (FindFriendsResult result in results)
                        {
                            if (result.hasResponded == false)
                                allComplete = false;
                        }
                        //All other servers have already responded, so complete the request
                        if (allComplete == true)
                        {
                            //Pass the request back up to the manager for completion, so it can remove this request from the queue
                            Managers.findFriendsManager.completeRequest(this);

                            return;
                        }
                    }
                }
            }
        }
        public void processResult(ServerSocketData fromServer, string xmlMessage)
        {
            bool allResultsRecieved = true;
            lock (results)
            {
                //Look through all the expected results and find the matching server
                foreach (FindFriendsResult ffr in results)
                {
                    if (ffr.server == fromServer)
                    {
                        //Flag this result as responded
                        ffr.hasResponded = true;

                        //Add xml data to the result
                        StringReader sr = new StringReader(xmlMessage);
                        XmlTextReader xmlReader = new XmlTextReader(sr);
                        while (xmlReader.Read())
                        {
                            if (xmlReader.Name == "frienddata")
                            {
                                FriendData fd = new FriendData();
                                fd.ID = int.Parse(xmlReader.GetAttribute("id").ToString());
                                fd.Name = xmlReader.GetAttribute("name").ToString();
                                fd.mapid = int.Parse(xmlReader.GetAttribute("mapid").ToString());
                                fd.instance = int.Parse(xmlReader.GetAttribute("instance").ToString());

                                ffr.friendsLocated.Add(fd);
                            }
                        }

                    }
                    if (ffr.hasResponded == false)
                        allResultsRecieved = false;
                }
            }
            if (allResultsRecieved)
                Managers.findFriendsManager.completeRequest(this);
        }

        public void completeRequest()
        {
            this.timerRequestTimeout.Stop();
            this.timerRequestTimeout.Dispose();

            StringWriter stringWriter = new StringWriter();
            XmlTextWriter xmldoc = new XmlTextWriter(stringWriter);

            //Sending the origional request result back, so origin is WS
            xmldoc.WriteStartElement("findfriendsresultWS");
            xmldoc.WriteAttributeString("friendsofId", friendsOfCharacterId.ToString());

            lock (results)
            {
                foreach (FindFriendsResult ffr in results)
                {
                    foreach (FriendData fd in ffr.friendsLocated)
                        xmldoc.WriteRaw(fd.toXML());
                }
            }

            xmldoc.WriteEndElement();
            xmldoc.Flush();
            xmldoc.Close();
            stringWriter.Flush();
            string xmlMessage = stringWriter.ToString();

            SocketConnectionsManager.sendToServer(_requesterServer, xmlMessage);
        }
    }
}
